/*
 * NetworkEventData.h
 *
 *  Created on: Sep 13, 2011
 *      Author: erudhes
 */

#ifndef NETWORKEVENTDATA_H_
#define NETWORKEVENTDATA_H_
#ifdef __WXGTK__
#include <netinet/in.h>
#endif
#include <wx/wx.h>

class wxSocketBase;
class wxSocketServer;

/**
 * This class hold the needed data for the communication between the server and the user
 *
 * @see IGameController
 * @author Rudolf Heszele heszele@gmail.com
 * @version 1.0
 * @since 2012-03-08
 */
class NetworkEventData
{
	public:
		/**
		 * Enumeration of the possible types of data sended over the network
		 */
		enum DataType
		{
			INVALID,					// The message is invalid, its type s not set yet
			CONNECTING,					// The server sends this type of message with the name of the hosting level
			CONNECTING_REJECT,			// The server sends this type of message when it is already serving a client
			CONNECTING_ACK,				// The client sends this type of message when the connection procedure is over
			CONFIGURATION,				// The server sends this type of message with the current configurations
			CONFIGURATION_ACK,			// The client sends this type of message with the negotiated frequency (see Configuration)
			RESTART,					// Both the client and the server can send this type of message to restart the current level
			NEW_LEVEL,					// The server sends this type of message to start a new level with the client
			NEW_LEVEL_ACK,				// The client sends this type of message if the change to the new level is finished
			NEW_LEVEL_REJECT,			// The client sends this type of message if the new level is not acceptable
			MOUSE_DOWN,					// The message contains the coordination where the user pushed down the LMB
			MOUSE_UP,					// The message contains the coordination where the user released the LMB
			MOUSE_MOTION,				// The message contains the coordination where the mouse pointer is
			MESSAGING,					// The message contains a messaging (text based data)
			DOWNLOADING_START,			// The client sends this type of message if it needs to download the level from the server
			DOWNLOADING_START_ACK,		// The server sends this type of message if it is able to upload the level
			DOWNLOADING_START_REJECT,	// The server sends this type of message if it is not able to upload the level
			DOWNLOADING_DATA,			// The message contains a piece of the level data - maximum one kilobyte - sent by the server
			DOWNLOADING_DATA_ACK,		// The client sends this type of message to acknowledge the received piece of data
			DOWNLOADING_END,			// The server sends this type of message when the upload of a file is finished
			KICK_OFF,					// The server sends this type of message if the user wants to kick off the client
		};
		/**
		 * The default constructor initializes the data member to invalid values.
		 *
		 * This constructor is mainly used on the "active" side, to send the data to  the remote side
		 */
		NetworkEventData();
		/**
		 * This constructor is used to create an object from the received buffer
		 *
		 * @param the buffer received from the remote side
		 */
		NetworkEventData(char* buffer);
		/**
		 * The destructor deletes the dynamically allocated data
		 */
		~NetworkEventData();
		DataType getDataType() const;
		void setDataType(DataType dataType);
		int getX() const;
		void setX(int x);
		int getY() const;
		void setY(int y);
		/**
		 * Getter to reach the additional data as a text
		 *
		 * @return The text representation of the additional data
		 */
		wxString getStringData() const;
		/**
		 * Getter to reach the additional data in a byte stream
		 *
		 * @return The pointer to the raw data
		 */
		const char* getRawData() const;
		/**
		 * Sets the additional data based on the received string parameter
		 *
		 * @param data The textual data to be sent over the network
		 */
		void setStringData(const wxString& data);
		/**
		 * This method is used to add data to be sent.
		 *
		 * This method can be used with string data and binary data as well.
		 * For string data no length needs to be added, but for binary data the length parameter is mandatory.
		 *
		 * @param data The string/binary data to be added
		 * @param length The length of the data. For string data it is optional, for binary data it is mandatory.
		 */
		void setRawData(const char* data, int length = -1);
		int getDataLength() const;
		/**
		 * Helper method to fill up the object from data read from the socket
		 *
		 * @param The socket to read the data from
		 */
		bool read(wxSocketBase* socket);
		/**
		 * Helper method to write the data member to the received socket
		 *
		 * @param The socket to write the data to
		 */
		bool write(wxSocketBase* socket);
		/**
		 * This method rejects the connection attempt
		 *
		 * This methods accepts the incoming connection but immediately sends a CONNECTING_REJECT packet
		 * and disconnects the client
		 *
		 * @param serverSocket The socket to accept the connection on
		 */
		void rejectConnection(wxSocketServer* serverSocket);

	private:
		DataType mDataType;
		int mX;
		int mY;
		/**
		 * The length of the additional data
		 */
		int mDataLength;
		/**
		 * Any kind of additional data - e.g.: The name of the level when a client is connected
		 */
		char* mData;
		/**
		 * To make the size of this class equal on 32 and 64 bits machines we need to add a dummy integer at the end of the class
		 * because the size of the pointer is different on these architectures. On 64 bits machines the pointer is 8 bytes,
		 * so the total size of the class is 24 byte. But on 32 bits machines the size of a pointer is 4 bytes, so we need to add
		 * a dummy integer which has a size of 4 bytes. So the size of the class will be 24 byte on 32 bits machines too.
		 * Integers have the same size on both architecture. It needs no initialization, since it is used nowhere.
		 */
#ifdef __I686__
		int mDummyData;
#endif
};

inline NetworkEventData::DataType NetworkEventData::getDataType() const
{
	return (DataType)ntohl(mDataType);
}

inline void NetworkEventData::setDataType(NetworkEventData::DataType dataType)
{
	mDataType = (DataType)htonl(dataType);
}

inline int NetworkEventData::getX() const
{
	return ntohl(mX);
}

inline void NetworkEventData::setX(int x)
{
	mX = htonl(x);
}

inline int NetworkEventData::getY() const
{
	return ntohl(mY);
}

inline void NetworkEventData::setY(int y)
{
	mY = htonl(y);
}

inline wxString NetworkEventData::getStringData() const
{
	if(NULL != mData)
		return wxString(mData, wxConvUTF8);
	return wxString(wxT(""));
}

inline const char* NetworkEventData::getRawData() const
{
	return mData;
}

inline void NetworkEventData::setStringData(const wxString& data)
{
	// Convert the string to UTF8 to get rid of endian-ness
	const wxCharBuffer charBuffer = data.ToUTF8();
	const char* tempLevel = charBuffer.data();

	this->setRawData(tempLevel);
}

inline void NetworkEventData::setRawData(const char* data, int length)
{
	if(NULL != mData)
		delete[] mData;
	if(-1 == length)
		mDataLength = strlen(data);
	else
		mDataLength = length;
	mData = new char[mDataLength + 1];
	memset(mData, 0, mDataLength + 1);
	if(-1 == length)
		strcpy(mData, data);
	else
		memcpy(mData, data, length);
	mDataLength = htonl(mDataLength);
}

inline int NetworkEventData::getDataLength() const
{
	return ntohl(mDataLength);
}

#endif /* NETWORKEVENTDATA_H_ */
